#include <iostream>
#include <string.h>
// 左值和右值
// 左值是表达式结束后依然存在的持久对象(代表一个在内存中占有确定位置的对象)
// 右值是表达式结束时不再存在的临时对象(不在内存中占有确定位置的表达式）
// 便携方法：对表达式取地址，如果能，则为左值，否则为右值

// std::move函数
// std::move作用主要可以将一个左值转换成右值引用，从而可以调用C++11右值引用的拷贝构造函数
// std::move应该是针对你的对象中有在堆上分配内存这种情况而设置的，如下

// 小结
// 在《Effective Modern C++》中建议：对于右值引用使用std::move，对于万能引用使用std::forward。
// std::move()与std::forward()都仅仅做了类型转换(可理解为static_cast转换)而已。真正的移动操作是在移动构造函数或者移动赋值操作符中发生的
// 在类型声明当中， “&&” 要不就是一个 rvalue reference ，要不就是一个 universal reference – 一种可以解析为lvalue reference或者rvalue reference的引用。
// 对于某个被推导的类型T，universal references 总是以 T&& 的形式出现。
// 引用折叠是 会让 universal references (其实就是一个处于引用折叠背景下的rvalue references ) 有时解析为 lvalue references 有时解析为 rvalue references 的根本机制。引用折叠只会在一些特定的可能会产生"引用的引用"场景下生效。
// 这些场景包括模板类型推导，auto 类型推导， typedef 的形成和使用，以及decltype 表达式。
class String
{
public:
    String(const char *buf)
    {
        _age = 10;
        _buf = new char[strlen(buf) + 1];
        strcpy(_buf, buf);
    }

    String(const String &str)
    {
        _age = 10;
        _buf = new char[strlen(str._buf) + 1];
        strcpy(_buf, str._buf);
    }

    // 右值引用版本
    String(String &&str)
    {
        _age = str._age;
        _buf = str._buf;
        str._buf = nullptr;
    }

    char *Data()
    {
        return _buf;
    }

private:
    char *_buf;
public:
    int _age;
};

String getString()
{
    String str("hello world!");
    return std::move(str); // 右值引用，无需重新申请变量，内存拷贝
}

int main(int argc, char const *argv[])
{
    // int i;
    // int &&j = i++; // 右值引用, i++
    // int &&k = ++i; 
    // int &m = i++;
    // int &l = ++i;

    String str("hello world!");
    printf(":-----> str %s\n", str.Data());
    String str1(str);
    printf(":-----> str %s str1 %s\n", str.Data(), str1.Data());
    String str2(std::move(str));
    printf(":-----> str %s:%d str2 %s\n", str.Data(), str._age, str2.Data());
    return 0;
}
